package com.ylw.project;

import com.ylw.project.constant.Project2CodeNameMappingEnum;
import com.ylw.util.Config;
import org.apache.log4j.Logger;
import org.junit.Test;

import java.io.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * project的工具类
 */
final public class Tools {

    private final static Logger log = Logger.getLogger(Tools.class);


    /**
     * 获取项目名称
     *
     * @param path
     * @return
     */
    public static String getProjectName(String path) {
        String projectName = "";
        projectName = getProjectName(path, (String) Config.getPropertValue("project.source.java.root").get(0));
        return projectName;
    }

    /**
     * 获取项目名称
     *
     * @param path
     * @param split
     * @return
     */
    public static String getProjectName(String path, String split) {
        String projectName = "";

        String reg = "\\\\([^\\\\]+)\\\\" + split + "\\\\.+";//windows下面
        if (isMacOs()) {
            reg = "/([^/]+)/" + split + "/.+";//macs
        }
        Pattern p = Pattern.compile(reg);
        Matcher m = p.matcher(path);
        if (m.find()) {
            projectName = m.group(1);
        }
        return projectName;
    }

    /**
     * 获取当前项目的真正路径  D:\ideaproject1\wap3.0
     *
     * @param javaPath
     * @return
     */
    public static String getProjectRealPath(String javaPath) {
        String projectName = "";
        String split = (String) Config.getPropertValue("project.source.java.root").get(0);
        String reg = "^(.+)\\\\" + split + "\\\\.+";
        if (isMacOs()) {
            reg = "^(.+)/" + split + "/.+";
        }
        Pattern p = Pattern.compile(reg);
        Matcher m = p.matcher(javaPath);
        if (m.find()) {
            projectName = m.group(1);
        }
        return projectName;
    }


    /**
     * 获取输出的项目根路径
     * D:\test\wap3.0.war
     * 这个方法需要改造，目前只适用于java
     *
     * @param javaPath
     * @return
     */
    public static String getOutputProjectRootRealPath(String javaPath, String split) {
        String projectName = Tools.getProjectName(javaPath, split);
        if ("".equals(projectName)) {
            return "";
        }
        String result = Config.getPropertValue("project.output.root").get(0) + File.separator + projectName + ".war";

//
//
///Users/away/work/hc/project/code_release_formal/zt_web-211_214.war/2019/10/10/wap3.0/zhuanti/guohu/js/apply.js
//                /Users/away/work/hc/project/code_release_formal/zt_web-211_214/2019/11/10/wap3.0.war/zhuanti/guohu/js/apply.js
//                /Users/away/work/hc/project/code_release_formal/default.war/2019/10/10/wt_jobs/WEB-INF/classes/com/ct10000/business/wt_order/job/JobActionJMJTOrder2WT.class

        if ("Y".equals(System.getProperty("fat"))) {
            String tmpDir = Config.getPropertValue("project.output.root.code").get(0) + File.separator;
            tmpDir += Project2CodeNameMappingEnum.getCodeNameByProjectName(projectName)
                    .getCodeRealDirName() + File.separator;
            Calendar instance = Calendar.getInstance();
            NumberFormat format = new DecimalFormat("00");
            tmpDir = tmpDir + instance.get(Calendar.YEAR) + File.separator +
                    format.format(instance.get(Calendar.MONTH) +1)+File.separator +
                    format.format( instance.get(Calendar.DAY_OF_MONTH) )+ File.separator;
            result = tmpDir +projectName+".war" ;

        }
        return result;
    }

    /**
     * 获取编译后的根路径
     * D:\ideaproject1\wap3.0\out\production\wap3.0
     *
     * @param javaPath
     * @return
     */
    public static String getCompileProjectRootRealPath(String javaPath) {
        String compileRP = "";
        compileRP = getProjectRealPath(javaPath) + File.separator + Config.getPropertValue("project.compile.root").get(0) + File.separator + getProjectName(javaPath);
        return compileRP;
    }


    /**
     * 获取lib的物理地址
     *
     * @param path javafilePath
     * @return
     */
    public static String getLibRealPath(String path) {
        String libRealPath = "";
        String javaRootSrc = (String) Config.getPropertValue("project.source.java.root").get(0);

        String[] temp = path.split("\\\\" + javaRootSrc + "\\\\");
        if (isMacOs()) {
            temp = path.split("/" + javaRootSrc + "/");
        }
        if (temp.length != 2) {
            return null;
        }
        File libDir = null;
        List<String> webSourceRoot = Config.getPropertValue("project.source.web.root");
        List<String> webLibRoot = Config.getPropertValue("project.source.lib.root");


        for (int i = 0; i < webSourceRoot.size(); i++) {
            for (int j = 0; j < webLibRoot.size(); j++) {
                libDir = new File(temp[0] + File.separator + webSourceRoot.get(i) + File.separator + webLibRoot.get(j));
                if (libDir.exists() && libDir.isDirectory()) {
                    return libDir.getPath();
                }
            }
        }
        return libRealPath;
    }


    /**
     * 获取该java文件的所有类路径
     *
     * @param classNames
     * @param parentPath class文件的父目录
     * @return
     */
    public static List<String> getAllClassPathForJava(List<String> classNames, String parentPath) {
        List<String> result = new ArrayList();
        for (String className : classNames) {
            result.add(parentPath + File.separator + className);
        }
        return result;
    }

    public static List<String> getAllClassPathForJava(String javaPath, String parentPath) {
        List<String> result = new ArrayList();
        List<String> classNames = getAllClassNameForJava(javaPath);
        for (String className : classNames) {
            result.add(parentPath + File.separator + className);
        }
        return result;
    }


    /**
     * 获取该java文件里面包含的所有类名称  包括非公用类和匿名类和内部类
     * 返回序列第一个肯定和java文件名称一致的类
     *
     * @param javaPath
     * @return
     */
    public static List<String> getAllClassNameForJava(String javaPath) {
        List<String> result = new ArrayList();
        String complierClassPath = getCompileClassFilePath(javaPath);
        LineNumberReader reader = null;
        try {
            //从java文件里面读取非共有的类  通过判断{是否消耗完成判断这个类是否结束以及下个类是否开始（都是指外部类）
            reader = new LineNumberReader(new InputStreamReader(new FileInputStream(javaPath)));
            String temp = "";
            //未匹配的大括号{符号数量
            int count = 0;
            while ((temp = reader.readLine()) != null) {
//                System.out.println(Thread.currentThread().getName() +"  "+ temp);
                //默认认为不会有一行出现两个大括号
                //当文件里面

                if (temp.contains("{")) {
                    if (count == 0) {
                        Pattern p = Pattern.compile("(class|interface|enum|@interface)[^\\w](\\w+)[^\\w]+(\\{|extends|implements).*");
                        Matcher m = p.matcher(temp);
                        if (m.find() && m.groupCount() == 3) {
                            result.add(m.group(2) + ".class");
                        }
                    }
                    count++;
                }
                if (temp.contains("}")) {
                    count--;
                }
                if (count < 0) {
                    log.error("parse java filecharset content is error");
                }
            }
            containInnerClass(complierClassPath, result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }


    /**
     * 通过java文件路径获取编译后的class文件路径,这里需要在config.properties里面配置顺序，
     * 因为在maven项目里面java目录在src\\main\\java这个目录下面，所以这个要配置在src前面
     *
     * @param javaPath
     * @return
     */
    public static String getCompileClassFilePath(String javaPath) {
        String classFilePath = "";
        List javaRoot = Config.getPropertValue("project.source.java.root");
        String classCompileRoot = (String) Config.getPropertValue("project.compile.root").get(0);
        for (Object java : javaRoot) {
            if (javaPath.contains(java.toString())) {
                classFilePath = javaPath.replace(java.toString(), classCompileRoot + File.separator + Tools.getProjectName(javaPath, (String) java));
            }
        }
        classFilePath = classFilePath.replace(".java", ".class");
        return classFilePath;
    }


    /**
     * 根据class路径判断该class是否包含内部类  当有的java文件没有编译的时候这个方法可能返回为值为空  需要在执行完编译后继续更新 java文件对应的类
     *
     * @param innerClassFiles 编译后的class路径
     * @return
     */
    public static boolean containInnerClass(String classFilePath, final List<String> innerClassFiles) {
        File classFile = new File(classFilePath);
        final String fileName = classFile.getName().replace(".class", "");

        File parentDir = classFile.getParentFile();
        String[] list = parentDir.list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                if (name.startsWith(fileName + "$")) {
                    innerClassFiles.add(name);
                    return true;
                }
                return false;
            }
        });
        if (list == null) {
            return false;
        }
        return list.length > 1;
    }


    /**
     * 判断文件是否修改，如果项目里面的文件修改了就需要更新
     *
     * @param newFilePath 项目里面的文件
     * @param oldFilePath 生成的war包文件
     * @return
     */
    public static boolean isModify(String newFilePath, String oldFilePath) {
        File newFile = new File(newFilePath);
        File oldFile = new File(oldFilePath);
        if (!oldFile.exists() || newFile.lastModified() > oldFile.lastModified()) {
            return true;
        }
        return false;
    }


    /**
     * 复制文件通过nio的Files类 当文件存在时 这里默认会覆盖文件
     *
     * @param sources
     * @param targets
     * @return
     */
    public static boolean copyFile(List<String> sources, List<String> targets) {
        boolean result = true;

        try {
            if (sources.size() != targets.size() || sources.size() == 0) {
                result = false;
            } else {
                for (int i = 0; i < sources.size(); i++) {
                    if (!copyFile(sources.get(i), targets.get(i))) {
                        throw new Exception();
                    }
                }
            }
        } catch (Exception e) {
            result = false;
            log.error("copy filecharset " + sources + " to " + targets + " fail.");
            e.printStackTrace();
        }
        return result;
    }

    public static boolean copyFile(String sourcePath, String targetPath) {
        log.info("copy  " + sourcePath + " ----> " + targetPath);
        File source = new File(sourcePath);
        File target = new File(targetPath);
        if (!source.exists()) {
            log.error(source + " not exist");
            return false;
        }
        if (source.lastModified() > target.lastModified()) {
            OutputStream out = null;
            InputStream in = null;
            try {

                if (!target.exists()) {
                    target.getParentFile().mkdirs();
                }
                /**
                 * 1.7
                 */
//                        Files.copy(Paths.get(sources.get(i)), Paths.get(targets.get(i)), StandardCopyOption.REPLACE_EXISTING);
                out = new FileOutputStream(target);
                in = new FileInputStream(source);
                byte[] b = new byte[1024];
                int temp = -1;
                while ((temp = in.read(b)) != -1) {
                    out.write(b, 0, temp);
                }
                out.flush();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    in.close();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    public static boolean isMacOs() {
        if ("Mac OS X".equals(System.getProperty("os.name"))) {
            return true;
        }
        return false;
    }


    public static void main(String[] args) {

        System.setProperty("fat", "Y");
        getOutputProjectRootRealPath("/Users/away/work/hc/project/bizdis_esb/src/com/ct10000/bizdis/app/guohu/GuohuService.java", (String) Config.getPropertValue("project.source.java.root").get(0));

        getAllClassNameForJava("D:\\ideaproject1\\wt_pay\\src\\com\\ct10000\\system\\annotations\\DomainNotNull.java");
//        String temp = "public class RechargeService extends DefaultAction {";
//        String temp = "public class ApplicationFilter implements Filter {";
//        String temp = "public class ApplicationFilter {";
        String temp = "public @interface DomainNotNull {";
//        Pattern p = Pattern.compile("([class|interface|enum])[^\\w](\\w+)[^\\w]+[{|extends].*");  //这里不能使用[]会这个中括号里面的|失效
        Pattern p = Pattern.compile("(class|interface|enum|@interface)[^\\w](\\w+)[^\\w]+(\\{|extends|implements).*");


        Matcher m = p.matcher(temp);
        if (m.matches()) {
            System.out.println(m.groupCount());
            for (int i = 0; i <= m.groupCount(); i++) {
                System.out.println(m.group(i));
            }
            System.out.println();
        }
        System.out.println("----------------");
        while (m.find()) {
            System.out.println(m.groupCount());
            for (int i = 0; i <= m.groupCount(); i++) {
                System.out.println(m.group(i));
            }
            System.out.println();
        }


        System.out.println(getProjectRealPath("D:\\ideaproject1\\wap3.0\\src\\com\\ct10000\\jobstart\\JobStart.java"));
        System.out.println(getOutputProjectRootRealPath("D:\\ideaproject1\\wap3.0\\src\\com\\ct10000\\jobstart\\JobStart.java", (String) Config.getPropertValue("project.source.java.root").get(0)));
        System.out.println(getCompileProjectRootRealPath("D:\\ideaproject1\\wap3.0\\src\\com\\ct10000\\jobstart\\JobStart.java"));
        System.out.println(getProjectName("D:\\asdf\\aa\\ss\\aa.java", "ss"));
        System.out.println(getLibRealPath("D:\\ideaproject1\\wap3.0\\src\\com\\ct10000\\jobstart\\JobStart.java"));
        System.out.println(getCompileProjectRootRealPath("D:\\ideaproject1\\wap3.0\\src\\com\\ct10000\\jobstart\\JobStart.java"));
    }
}

